<template>
  <div class="asr-container">
    <div class="header-section">
      <h1>🎙️ 语音识别服务</h1>
      <p>基于 Spring Boot 3 的说话人分割与语音识别系统</p>
    </div>
    <el-card class="box-card">

      <!-- 文件上传区域 -->
      <el-card class="section-card" shadow="never">
        <template #header>
          <span>📁 上传音频文件</span>
        </template>
        <el-upload
          ref="uploadRef"
          class="upload-demo"
          :before-upload="beforeUpload"
          :file-list="fileList"
          :on-change="handleFileChange"
          multiple
          accept="audio/*"
          :auto-upload="false"
          :show-file-list="true"
        >
          <el-button type="primary" :loading="isUploading">
            {{ isUploading ? '正在上传...' : '选择音频文件（选择后自动上传）' }}
          </el-button>
          <template #tip>
            <div class="el-upload__tip">
              支持 WAV, MP3, FLAC, OGG, M4A 等格式，选择文件后会自动上传
            </div>
          </template>
        </el-upload>
        
        <!-- 显示已上传的文件 -->
        <div v-if="uploadedFiles.length > 0" class="uploaded-files">
          <h4>✅ 已上传的文件 ({{ uploadedFiles.length }} 个)：</h4>
          <ul>
            <li v-for="(file, index) in uploadedFiles" :key="index">
              {{ getFileName(file) }}
            </li>
          </ul>
        </div>
      </el-card>

      <!-- 配置选项 -->
      <el-card class="section-card" shadow="never">
        <template #header>
          <span>⚙️ 配置选项</span>
        </template>
        <el-form :model="config" label-width="120px">
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="ASR 模型">
                <el-select v-model="config.modelId" placeholder="请选择模型" style="width: 100%">
                  <el-option
                    v-for="model in models"
                    :key="model.id"
                    :label="`${model.name} - ${model.description}`"
                    :value="model.id"
                  />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="语言">
                <el-select v-model="config.language" style="width: 100%">
                  <el-option label="自动检测" value="auto" />
                  <el-option label="中文（国语）" value="zh" />
                  <el-option label="粤语" value="yue" />
                </el-select>
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="说话人数量">
                <el-input-number
                  v-model="config.numSpeakers"
                  :min="-1"
                  :max="20"
                  style="width: 100%"
                />
                <div class="form-tip">-1 表示自动检测</div>
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="聚类阈值">
                <el-input-number
                  v-model="config.clusterThreshold"
                  :min="0"
                  :max="1"
                  :step="0.1"
                  style="width: 100%"
                />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row :gutter="20">
            <el-col :span="12">
              <el-form-item label="并行进程数">
                <el-input-number
                  v-model="config.numProcesses"
                  :min="1"
                  :max="16"
                  style="width: 100%"
                />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item label="GPU 数量">
                <el-input-number
                  v-model="config.numGpus"
                  :min="1"
                  :max="8"
                  style="width: 100%"
                />
              </el-form-item>
            </el-col>
          </el-row>
          <el-form-item>
            <el-button
              type="primary"
              size="large"
              :disabled="!canStartTask"
              :loading="isProcessing"
              @click="startTask"
            >
              🚀 开始识别
            </el-button>
          </el-form-item>
        </el-form>
      </el-card>

      <!-- 进度显示 -->
      <el-card v-if="showProgress" class="section-card" shadow="never">
        <template #header>
          <span>📊 处理进度</span>
        </template>
        <div class="progress-container">
          <div
            v-for="(progress, index) in progressList"
            :key="index"
            class="progress-item"
          >
            <div class="progress-header">
              <span class="progress-file">{{ progress.fileName }}</span>
              <el-tag :type="getStageType(progress.stage)">
                {{ getStageText(progress.stage) }}
              </el-tag>
            </div>
            <el-progress
              :percentage="progress.progress"
              :status="progress.stage === 'error' ? 'exception' : undefined"
            />
            <div class="progress-message">
              {{ progress.message }} (GPU {{ progress.gpuId }})
            </div>
          </div>
        </div>
      </el-card>

      <!-- 结果显示 -->
      <el-card v-if="showResults" class="section-card" shadow="never">
        <template #header>
          <span>✅ 处理结果</span>
        </template>
        <div class="results-container">
          <!-- 总体统计 -->
          <el-card class="stats-card" shadow="never">
            <template #header>
              <span>📈 总体统计</span>
            </template>
            <el-row :gutter="20">
              <el-col :span="6">
                <div class="stat-item">
                  <div class="stat-value">{{ taskResult.audioFiles?.length || 0 }}</div>
                  <div class="stat-label">处理文件数</div>
                </div>
              </el-col>
              <el-col :span="6">
                <div class="stat-item">
                  <div class="stat-value">
                    {{ taskResult.totalDuration ? taskResult.totalDuration.toFixed(2) + 's' : 'N/A' }}
                  </div>
                  <div class="stat-label">总时长</div>
                </div>
              </el-col>
              <el-col :span="6">
                <div class="stat-item">
                  <div class="stat-value">
                    {{ taskResult.processingTime ? taskResult.processingTime.toFixed(2) + 's' : 'N/A' }}
                  </div>
                  <div class="stat-label">处理时间</div>
                </div>
              </el-col>
              <el-col :span="6">
                <div class="stat-item">
                  <div class="stat-value">
                    {{ taskResult.overallRtf ? taskResult.overallRtf.toFixed(3) : 'N/A' }}
                  </div>
                  <div class="stat-label">实时率 (RTF)</div>
                </div>
              </el-col>
            </el-row>
          </el-card>

          <!-- 输出文件列表 -->
          <el-card v-if="taskResult.resultFiles?.length" class="files-card" shadow="never">
            <template #header>
              <span>📄 输出文件</span>
            </template>
            <el-list>
              <el-list-item
                v-for="(file, index) in taskResult.resultFiles"
                :key="index"
                class="file-item"
              >
                <span>{{ getFileName(file) }}</span>
                <el-icon color="#67C23A"><Check /></el-icon>
              </el-list-item>
            </el-list>
          </el-card>
        </div>
      </el-card>
    </el-card>
  </div>
</template>

<script setup name="ASR">
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Check } from '@element-plus/icons-vue'
import { asrApi } from '@/api/asr'

// 响应式数据
const uploadRef = ref()
const fileList = ref([])
const selectedFiles = ref([])
const uploadedFiles = ref([])
const models = ref([])
const isUploading = ref(false)
const isProcessing = ref(false)
const showProgress = ref(false)
const showResults = ref(false)
const progressList = ref([])
const taskResult = ref({})
const currentTaskId = ref(null)
let websocket = null

// 配置选项
const config = reactive({
  modelId: '',
  language: 'auto',
  numSpeakers: -1,
  clusterThreshold: 0.7,
  numProcesses: 1,
  numGpus: 1
})

// 计算属性
const uploadUrl = computed(() => 'http://localhost:8080/api/files/upload/batch')
const uploadHeaders = computed(() => ({
  'Content-Type': 'multipart/form-data'
}))
const canStartTask = computed(() => uploadedFiles.value.length > 0 && config.modelId && !isProcessing.value)

// 生命周期
onMounted(() => {
  loadModels()
})

onUnmounted(() => {
  if (websocket) {
    websocket.close()
  }
})

// 方法
const loadModels = async () => {
  try {
    const response = await asrApi.getModels()
    models.value = response.data
    if (models.value.length > 0) {
      config.modelId = models.value[0].id
    }
  } catch (error) {
    ElMessage.error('加载模型失败: ' + error.message)
  }
}

const beforeUpload = (file) => {
  const isAudio = file.type.startsWith('audio/')
  if (!isAudio) {
    ElMessage.error('只能上传音频文件!')
    return false
  }
  return true
}

const handleFileChange = async (file, fileList) => {
  console.log('文件变化:', file, fileList)
  selectedFiles.value = fileList.map(f => f.raw).filter(Boolean)
  
  // 如果有文件选择，自动上传
  if (selectedFiles.value.length > 0) {
    await uploadFiles()
  }
}

const uploadFiles = async () => {
  if (selectedFiles.value.length === 0) {
    ElMessage.error('请选择文件')
    return
  }
  
  if (isUploading.value) {
    ElMessage.warning('正在上传中，请稍候...')
    return
  }
  
  isUploading.value = true
  ElMessage.info('正在上传文件...')
  
  const formData = new FormData()
  selectedFiles.value.forEach(file => {
    formData.append('files', file)
  })
  
  try {
    console.log('开始上传文件:', selectedFiles.value.map(f => f.name))
    console.log('FormData内容:')
    for (let pair of formData.entries()) {
      console.log(pair[0], pair[1])
    }
    
    // 使用原生fetch上传
    const response = await fetch('http://localhost:8080/api/files/upload/batch', {
      method: 'POST',
      body: formData
      // 不设置Content-Type，让浏览器自动设置
    })
    
    console.log('响应状态:', response.status)
    const result = await response.json()
    console.log('上传响应:', result)
    
    if (response.ok && result.code === 200) {
      uploadedFiles.value = result.data
      ElMessage.success(`成功上传 ${selectedFiles.value.length} 个文件`)
      
      // 清空选择的文件
      selectedFiles.value = []
      fileList.value = []
      if (uploadRef.value?.clearFiles) {
        uploadRef.value.clearFiles()
      }
    } else {
      ElMessage.error('上传失败: ' + (result.message || '未知错误'))
    }
  } catch (error) {
    console.error('上传失败:', error)
    ElMessage.error('上传失败: ' + error.message)
  } finally {
    isUploading.value = false
  }
}


const handleUploadSuccess = (response, file, fileList) => {
  console.log('上传成功响应:', response)
  if (response.code === 200) {
    uploadedFiles.value = response.data
    ElMessage.success(`成功上传 ${uploadedFiles.value.length} 个文件`)
  } else {
    ElMessage.error('上传失败: ' + (response.message || '未知错误'))
  }
}

const handleUploadError = (error) => {
  console.error('上传错误:', error)
  let errorMessage = '上传失败'
  
  if (error.response) {
    try {
      const errorData = JSON.parse(error.response)
      errorMessage = errorData.message || errorMessage
    } catch (e) {
      errorMessage = error.response
    }
  } else if (error.message) {
    errorMessage = error.message
  }
  
  ElMessage.error(errorMessage)
}

const startTask = async () => {
  if (uploadedFiles.value.length === 0) {
    ElMessage.error('请先上传音频文件')
    return
  }

  try {
    isProcessing.value = true
    showProgress.value = true
    showResults.value = false

    // 获取选中的模型配置
    const modelResponse = await asrApi.getModel(config.modelId)
    const model = modelResponse.data

    // 获取说话人模型配置
    const speakerResponse = await asrApi.getSpeakerModel()
    const speaker = speakerResponse.data

    // 构建请求
    const taskConfig = {
      speakerSegmentationModel: speaker.segmentation,
      speakerEmbeddingModel: speaker.embedding,
      asrModelPath: model.modelPath,
      asrTokensPath: model.tokensPath,
      asrModelType: model.type,
      numSpeakers: config.numSpeakers,
      clusterThreshold: config.clusterThreshold,
      language: config.language,
      numProcesses: config.numProcesses,
      numGpus: config.numGpus,
      provider: 'cuda'
    }

    // 只有 Whisper 模型才添加 encoder 和 decoder
    if (model.encoderPath) {
      taskConfig.whisperEncoder = model.encoderPath
    }
    if (model.decoderPath) {
      taskConfig.whisperDecoder = model.decoderPath
    }

    const request = {
      audioFiles: uploadedFiles.value,
      config: taskConfig
    }

    // 创建任务
    const response = await asrApi.createTask(request)
    if (response.code === 200) {
      currentTaskId.value = response.data.taskId
      ElMessage.success('任务创建成功，开始处理...')

      // 初始化进度显示
      initProgressDisplay(uploadedFiles.value)

      // 连接 WebSocket 监听进度
      connectWebSocket(currentTaskId.value)
    } else {
      ElMessage.error('创建任务失败: ' + response.message)
      isProcessing.value = false
    }
  } catch (error) {
    ElMessage.error('创建任务失败: ' + error.message)
    isProcessing.value = false
  }
}

const initProgressDisplay = (files) => {
  progressList.value = files.map((filePath) => ({
    fileName: getFileName(filePath),
    progress: 0,
    stage: 'loading',
    message: '等待开始...',
    gpuId: 0
  }))
}

const connectWebSocket = (taskId) => {
  // 暂时禁用WebSocket，使用轮询方式获取进度
  console.log('WebSocket功能暂时禁用，使用轮询方式')
  
  // 每2秒轮询一次任务状态
  const pollInterval = setInterval(async () => {
    try {
      const response = await asrApi.getTaskStatus(taskId)
      const task = response.data || response
      
      if (task.status === 'COMPLETED' || task.status === 'FAILED') {
        clearInterval(pollInterval)
        handleTaskComplete(task)
      }
    } catch (error) {
      console.error('轮询任务状态失败:', error)
    }
  }, 2000)
  
  // 保存轮询ID以便清理
  websocket = { close: () => clearInterval(pollInterval) }
}

const updateProgress = (progress) => {
  const index = progressList.value.findIndex(p => p.fileName === progress.fileName)
  if (index !== -1) {
    progressList.value[index] = {
      ...progressList.value[index],
      progress: progress.progress,
      stage: progress.stage,
      message: progress.message,
      gpuId: progress.gpuId
    }
  }
}

const handleTaskComplete = (task) => {
  console.log('任务完成:', task)

  if (task.status === 'COMPLETED') {
    ElMessage.success('所有文件处理完成！')
    taskResult.value = task
    showResults.value = true
  } else if (task.status === 'FAILED') {
    ElMessage.error('任务失败: ' + task.errorMessage)
  }

  isProcessing.value = false

  // 停止轮询
  if (websocket) {
    websocket.close()
  }
}

const getStageText = (stage) => {
  const stageMap = {
    'loading': '加载中',
    'diarization': '说话人分割',
    'recognition': '语音识别',
    'completed': '已完成',
    'error': '错误'
  }
  return stageMap[stage] || stage
}

const getStageType = (stage) => {
  const typeMap = {
    'loading': 'warning',
    'diarization': 'primary',
    'recognition': 'info',
    'completed': 'success',
    'error': 'danger'
  }
  return typeMap[stage] || 'info'
}

const getFileName = (filePath) => {
  return filePath.split(/[/\\]/).pop()
}
</script>

<style scoped>
.asr-container {
  min-height: 100vh;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  padding: 20px;
}

.header-section {
  text-align: center;
  color: white;
  margin-bottom: 30px;
}

.header-section h1 {
  font-size: 32px;
  margin-bottom: 10px;
  text-shadow: 0 2px 4px rgba(0,0,0,0.3);
}

.header-section p {
  font-size: 16px;
  opacity: 0.9;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.section-card {
  margin-bottom: 20px;
}

.form-tip {
  font-size: 12px;
  color: #909399;
  margin-top: 4px;
}

.progress-container {
  space-y: 16px;
}

.progress-item {
  padding: 16px;
  background: #f8f9fa;
  border-radius: 8px;
  margin-bottom: 16px;
}

.progress-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}

.progress-file {
  font-weight: 600;
  color: #303133;
}

.progress-message {
  font-size: 14px;
  color: #909399;
  margin-top: 8px;
}

.results-container {
  space-y: 16px;
}

.stats-card,
.files-card {
  margin-bottom: 16px;
}

.stat-item {
  text-align: center;
  padding: 16px;
  background: #f8f9fa;
  border-radius: 8px;
}

.stat-value {
  font-size: 24px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 4px;
}

.stat-label {
  font-size: 14px;
  color: #909399;
}

.file-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 0;
}

.uploaded-files {
  margin-top: 20px;
  padding: 15px;
  background: #f0f9ff;
  border-radius: 8px;
  border: 1px solid #bfdbfe;
}

.uploaded-files h4 {
  color: #1e40af;
  margin-bottom: 10px;
}

.uploaded-files ul {
  margin: 0;
  padding-left: 20px;
}

.uploaded-files li {
  color: #374151;
  margin-bottom: 5px;
}
</style>
